/**
 * 日志核心功能模块
 * 负责日志文件的创建、写入、轮转等核心功能
 */

const fs = require('fs');
const path = require('path');
const { DataMasker } = require('./data-masker');

// 导入工具函数
const { ensureDirectoryExists, generateRequestId, formatDate } = require('./utils');

// 从统一配置模块中获取配置
const config = require('../../config');
const loggerConfig = config.logger || {};
const LOG_LEVELS = loggerConfig.LOG_LEVELS || {
  ERROR: 'error',
  WARN: 'warn',
  INFO: 'info',
  DEBUG: 'debug'
};
const LOG_DIR = loggerConfig.LOG_DIR || path.join(process.cwd(), 'logs');
const ERROR_LOG_DIR = loggerConfig.ERROR_LOG_DIR || path.join(LOG_DIR, 'error');
const OUTPUT_LOG_DIR = loggerConfig.OUTPUT_LOG_DIR || path.join(LOG_DIR, 'output');

// 确保日志目录存在
ensureDirectoryExists(ERROR_LOG_DIR);
ensureDirectoryExists(OUTPUT_LOG_DIR);

// 创建数据脱敏实例
const dataMasker = new DataMasker();

/**
 * 获取日志文件路径
 * @param {string} type - 日志类型（error/output）
 * @returns {string} - 日志文件路径
 */
function getLogFilePath(type) {
  const today = new Date();
  const dateStr = formatDate(today, 'yyyy-MM-dd');
  const directory = type === 'error' ? ERROR_LOG_DIR : OUTPUT_LOG_DIR;
  return path.join(directory, `${dateStr}.log`);
}

/**
 * 写入日志到文件
 * @param {string} type - 日志类型（error/output）
 * @param {string} content - 日志内容
 */
function writeLogToFile(type, content) {
  try {
    const logFilePath = getLogFilePath(type);
    // 添加时间戳
    const timestamp = formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss.SSS');
    const logEntry = `[${timestamp}] ${content}\n`;
    
    // 写入日志文件
    fs.appendFileSync(logFilePath, logEntry, 'utf8');
  } catch (error) {
    // 如果写入文件失败，输出到控制台
    console.error('写入日志文件失败:', error);
  }
}

/**
 * 检查并执行日志轮转
 * @param {string} logFilePath - 日志文件路径
 */
function checkLogRotation(logFilePath) {
  try {
    // 检查文件是否存在
    if (!fs.existsSync(logFilePath)) {
      return;
    }
    
    // 获取文件大小（字节）
    const stats = fs.statSync(logFilePath);
    const fileSizeInBytes = stats.size;
    const fileSizeInMB = fileSizeInBytes / (1024 * 1024);
    
    // 如果文件大小超过10MB，则进行轮转
    const MAX_FILE_SIZE_MB = 10;
    if (fileSizeInMB >= MAX_FILE_SIZE_MB) {
      // 创建轮转文件名
      const timestamp = formatDate(new Date(), 'yyyyMMddHHmmss');
      const dirname = path.dirname(logFilePath);
      const basename = path.basename(logFilePath, '.log');
      const rotatedFileName = path.join(dirname, `${basename}_${timestamp}.log`);
      
      // 重命名文件
      fs.renameSync(logFilePath, rotatedFileName);
    }
  } catch (error) {
    console.error('日志轮转失败:', error);
  }
}

/**
 * 格式化日志内容
 * @param {string} level - 日志级别
 * @param {string} message - 日志消息
 * @param {object} data - 附加数据
 * @param {string} requestId - 请求ID
 * @returns {string} - 格式化后的日志内容
 */
function formatLogContent(level, message, data = null, requestId = null) {
  let content = `[${level.toUpperCase()}]`;
  
  if (requestId) {
    content += ` [RequestID: ${requestId}]`;
  }
  
  content += ` ${message}`;
  
  if (data) {
    try {
      // 对数据进行脱敏处理
      const maskedData = dataMasker.maskObject(data);
      content += ` ${JSON.stringify(maskedData)}`;
    } catch (error) {
      content += ` [数据序列化失败]`;
    }
  }
  
  return content;
}

/**
 * 日志核心类
 * 提供各种级别的日志记录功能
 */
class LoggerCore {
  constructor() {
    this.dataMasker = dataMasker;
  }
  
  /**
   * 记录debug级别日志
   * @param {string} message - 日志消息
   * @param {object} data - 附加数据
   * @param {string} requestId - 请求ID
   */
  debug(message, data = null, requestId = null) {
    const content = formatLogContent(LOG_LEVELS.DEBUG, message, data, requestId);
    console.log(content);
    writeLogToFile('output', content);
  }
  
  /**
   * 记录info级别日志
   * @param {string} message - 日志消息
   * @param {object} data - 附加数据
   * @param {string} requestId - 请求ID
   */
  info(message, data = null, requestId = null) {
    const content = formatLogContent(LOG_LEVELS.INFO, message, data, requestId);
    console.log(content);
    writeLogToFile('output', content);
  }
  
  /**
   * 记录warn级别日志
   * @param {string} message - 日志消息
   * @param {object} data - 附加数据
   * @param {string} requestId - 请求ID
   */
  warn(message, data = null, requestId = null) {
    const content = formatLogContent(LOG_LEVELS.WARN, message, data, requestId);
    console.warn(content);
    writeLogToFile('output', content);
  }
  
  /**
   * 记录error级别日志
   * @param {string|Error} message - 日志消息或错误对象
   * @param {object} data - 附加数据
   * @param {string} requestId - 请求ID
   */
  error(message, data = null, requestId = null) {
    let errorMessage;
    let errorStack = null;
    
    if (message instanceof Error) {
      errorMessage = message.message;
      errorStack = message.stack;
    } else {
      errorMessage = message;
    }
    
    const content = formatLogContent(LOG_LEVELS.ERROR, errorMessage, data, requestId);
    console.error(content);
    writeLogToFile('error', content);
    
    // 如果有错误堆栈，也记录下来
    if (errorStack) {
      writeLogToFile('error', `[ERROR_STACK] ${errorStack}`);
    }
  }
  
  /**
   * 记录HTTP请求日志
   * @param {object} req - Express请求对象
   * @param {object} res - Express响应对象
   * @param {number} responseTime - 响应时间（毫秒）
   */
  logRequest(req, res, responseTime) {
    const { method, url, headers, body } = req;
    const { statusCode } = res;
    
    // 构建日志数据
    const logData = {
      method,
      url,
      statusCode,
      responseTime,
      ip: headers['x-forwarded-for'] || req.connection.remoteAddress,
      userAgent: headers['user-agent']
    };
    
    // 只在debug级别记录请求体
    const level = statusCode >= 500 ? LOG_LEVELS.ERROR : 
                  statusCode >= 400 ? LOG_LEVELS.WARN : LOG_LEVELS.INFO;
    
    // 对于info和warn级别，不记录请求体
    let requestBody = null;
    if (level === LOG_LEVELS.ERROR || level === LOG_LEVELS.DEBUG) {
      requestBody = body;
    }
    
    const requestId = req.headers['x-request-id'] || generateRequestId();
    const message = `HTTP ${method} ${url} ${statusCode} ${responseTime}ms`;
    
    // 根据级别记录日志
    if (level === LOG_LEVELS.ERROR) {
      this.error(message, { ...logData, body: requestBody }, requestId);
    } else if (level === LOG_LEVELS.WARN) {
      this.warn(message, logData, requestId);
    } else if (level === LOG_LEVELS.DEBUG) {
      this.debug(message, { ...logData, body: requestBody }, requestId);
    } else {
      this.info(message, logData, requestId);
    }
  }
  
  /**
   * 检查并执行所有日志文件的轮转
   */
  rotateLogs() {
    checkLogRotation(getLogFilePath('error'));
    checkLogRotation(getLogFilePath('output'));
  }
}

/**
 * 通用日志记录函数 - 兼容原logger.js中的log函数
 * @param {number} level - 日志级别
 * @param {string} message - 日志消息
 * @param {Object} meta - 附加元数据
 */
function log(level, message, meta = {}) {
  // 从数字级别映射到字符串级别
  let levelStr;
  switch(level) {
    case 0: levelStr = LOG_LEVELS.ERROR; break;
    case 1: levelStr = LOG_LEVELS.WARN; break;
    case 2: levelStr = LOG_LEVELS.INFO; break;
    case 3: levelStr = LOG_LEVELS.DEBUG; break;
    default: levelStr = LOG_LEVELS.INFO;
  }
  
  const timestamp = new Date().toISOString();
  
  // 使用dataMasker实例进行脱敏
  const sanitizedMeta = dataMasker.maskObject(meta);
  
  // 统一的结构化日志格式
  const logEntry = {
    timestamp,
    level: levelStr.toUpperCase(),
    message,
    app_id: process.env.APP_ID || 'node-express-mysql',
    service_name: process.env.SERVICE_NAME || 'backend-api',
    environment: process.env.NODE_ENV || 'development',
    correlation_id: sanitizedMeta.correlation_id || 'unknown',
    ...(sanitizedMeta.correlation_id ? (({ correlation_id, ...rest }) => rest)(sanitizedMeta) : sanitizedMeta)
  };
  
  // 将日志对象转换为字符串
  const logString = JSON.stringify(logEntry);
  
  // 根据级别写入对应文件
  const logFilePath = getLogFilePath(levelStr === LOG_LEVELS.ERROR ? 'error' : 'output');
  
  // 检查日志轮转
  checkLogRotation(logFilePath);
  
  try {
    fs.appendFileSync(logFilePath, logString + '\n', 'utf8');
    
    // 同时输出到控制台，以便在浏览器调试时能看到日志
    // 使用对应的控制台方法
    if (level === 0) { // ERROR
      console.error(logEntry);
    } else if (level === 1) { // WARN
      console.warn(logEntry);
    } else if (level === 3) { // DEBUG
      console.debug(logEntry);
    } else { // INFO
      console.log(logEntry);
    }
  } catch (err) {
    console.error(`[LOGGER ERROR] Failed to write to log file: ${err.message}`);
  }
}

module.exports = {
  LoggerCore,
  LOG_LEVELS,
  LOG_DIR,
  ERROR_LOG_DIR,
  OUTPUT_LOG_DIR,
  log // 导出log函数以兼容原logger.js
};